﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MethodWorx.CMS.Plugins;
using System.Data.Linq;
using MethodWorx.Core.DomainModel;
using MethodWorx.Core.Linq;

namespace MethodWorx.CMS.Linq
{
    public class LinqPluginUserDataRepository : LinqGenericStorageRepository<PluginUserData>, IPluginUserDataRepository
    {
        public LinqPluginUserDataRepository(DataContext context)
            : base(context)
        {
        }

        protected override string Type
        {
            get { return "PluginUserData"; }
        }

        protected override IEnumerable<LinqGenericStorageIndex> GetIndexes(PluginUserData entity)
        {
            yield return new LinqGenericStorageIndex() { Id = Guid.NewGuid(), GenericStorageId = entity.Id, Name = "PluginId", Type = this.Type, Value = entity.PluginId.ToString() };
            yield return new LinqGenericStorageIndex() { Id = Guid.NewGuid(), GenericStorageId = entity.Id, Name = "EntityId", Type = this.Type, Value = ((entity.EntityId == null) ? null : entity.EntityId.ToString()) };
            yield return new LinqGenericStorageIndex() { Id = Guid.NewGuid(), GenericStorageId = entity.Id, Name = "UserDataType", Type = this.Type, Value = entity.UserDataType };
        }


        /// <summary>
        /// Fid plugin user data by using the indexing system of the generic storage
        /// </summary>
        /// <param name="plugin"></param>
        /// <param name="entity"></param>
        /// <param name="userDataType"></param>
        /// <returns></returns>
        public PluginUserData FindPluginUserData(IPlugin plugin, Core.DomainModel.AggregateRoot entity, string userDataType)
        {
            if(plugin == null)
                throw new ArgumentException("plugin");

            if(string.IsNullOrEmpty("userDataType"))
                throw new ArgumentNullException("userDataType");

            var query = from i1 in this.Indexes.Where(i => i.Name == "PluginId" && i.Type == this.Type && i.Value == plugin.Id.ToString())
                        join i2 in this.Indexes.Where(i => i.Name == "UserDataType" && i.Type == this.Type && i.Value == userDataType)
                            on i1.GenericStorageId equals i2.GenericStorageId
                        select i1;

            if (entity != null)
            {
                query = from i1 in query
                        join i2 in this.Indexes.Where(i => i.Name == "EntityId" && i.Type == this.Type && i.Value == entity.Id.ToString())
                            on i1.GenericStorageId equals i2.GenericStorageId
                        select i1;
            }
            else
            {
                query = from i1 in query
                        join i2 in this.Indexes.Where(i => i.Name == "EntityId" && i.Type == this.Type && i.Value == null)
                            on i1.GenericStorageId equals i2.GenericStorageId
                        select i1;
            }

            LinqGenericStorageIndex index = query.FirstOrDefault();
            if(index != null)
                return this[index.GenericStorageId];
            else
                return null;
        }

        /// <summary>
        /// Fid plugin user data by using the indexing system of the generic storage
        /// </summary>
        /// <param name="plugin"></param>
        /// <param name="entity"></param>
        /// <param name="userDataType"></param>
        /// <returns></returns>
        public IEnumerable<PluginUserData> FindAllPluginUserData(IPlugin plugin, Core.DomainModel.AggregateRoot entity, string userDataType)
        {
            if (plugin == null)
                throw new ArgumentException("plugin");

            if (string.IsNullOrEmpty("userDataType"))
                throw new ArgumentNullException("userDataType");

            var query = from i1 in this.Indexes.Where(i => i.Name == "PluginId" && i.Type == this.Type && i.Value == plugin.Id.ToString())
                        join i2 in this.Indexes.Where(i => i.Name == "UserDataType" && i.Type == this.Type && i.Value == userDataType)
                            on i1.GenericStorageId equals i2.GenericStorageId
                        select i1;

            if (entity != null)
            {
                query = from i1 in query
                        join i2 in this.Indexes.Where(i => i.Name == "EntityId" && i.Type == this.Type && i.Value == entity.Id.ToString())
                            on i1.GenericStorageId equals i2.GenericStorageId
                        select i1;
            }
            else
            {
                query = from i1 in query
                        join i2 in this.Indexes.Where(i => i.Name == "EntityId" && i.Type == this.Type && i.Value == null)
                            on i1.GenericStorageId equals i2.GenericStorageId
                        select i1;
            }

            foreach(var index in query)
                yield return this[index.GenericStorageId];
        }


        public IEnumerable<PluginUserData> FindAllPluginUserData(AggregateRoot entity)
        {
            foreach (var index in this.Indexes.Where(i => i.Name == "EntityId" && i.Type == this.Type && i.Value == entity.Id.ToString()))
                yield return this[index.GenericStorageId];
        }
    }
}
